#include <touchgfx/hal/OSWrappers.hpp>
#include <STM32F1HAL.hpp>
#include <touchgfx/lcd/LCD.hpp>
#include <touchgfx/hal/GPIO.hpp>

uint16_t *STM32F1HAL::getTFTFrameBuffer() const
{
    return (uint16_t *)(0xD0000000);
}

void STM32F1HAL::setTFTFrameBuffer(uint16_t *adr)
{
}

uint16_t STM32F1HAL::getTFTCurrentLine()
{
    // This function only requires an implementation if single buffering
    // on LTDC display is being used (REFRESH_STRATEGY_OPTIM_SINGLE_BUFFER_TFT_CTRL).

    // The CPSR register (bits 15:0) specify current line of TFT controller.
    uint16_t curr = 0;       // (uint16_t)(LTDC->CPSR & 0xffff);
    uint16_t backPorchY = 1; // (uint16_t)(LTDC->BPCR & 0x7FF) + 1;

    // The semantics of the getTFTCurrentLine() function is to return a value
    // in the range of 0-totalheight. If we are still in back porch area, return 0.
    if (curr < backPorchY)
    {
        return 0;
    }
    else
    {
        return curr - backPorchY;
    }
}

void STM32F1HAL::flushFrameBuffer(const touchgfx::Rect &rect)
{
    HAL::flushFrameBuffer(rect);
    ili9327.setAddrWindow(rect.x, rect.y, rect.width, rect.height);
    displayXferFB(rect.x, rect.y, rect.width, rect.height, Bank1_ili9327_D);
}

void STM32F1HAL::configureInterrupts()
{
    // NVIC_SetPriority(LCD_TE_IRQn, 9);
}

static uint16_t lcd_int_active_line;
static uint16_t lcd_int_porch_line;

/* Enable LCD line interrupt, when entering video (active) area */
void STM32F1HAL::enableLCDControllerInterrupt()
{
    // NVIC_EnableIRQ(LCD_TE_IRQn);
}

void STM32F1HAL::disableInterrupts()
{
    // NVIC_DisableIRQ(LCD_TE_IRQn);
}

void STM32F1HAL::enableInterrupts()
{
}
  inline void writedata(uint16_t c)
  {
    *(volatile unsigned short *)Bank1_ili9327_D = c;
  }
void displayXferFB(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t frameBufferStart)
{
    __IO uint32_t write_pointer = (uint32_t)(DISP_HOR_RESOLUTION * y + x);

    uint32_t _area = (uint32_t)width * height;
    uint32_t tdcSize = (uint32_t)2 * width; //SSD2805 specific, set payload in bytes

    // writeTDCSize(tdcSize); //SSD2805 specific

    //set DCS write command (write command DCS_RAMWR)
    // writecommand(DCS_RAMWR); //8080-IF with DCS_RAMWR to start writing to SRAM of SSD2805

    while (_area--)
    {
        writedata(*(__IO uint16_t *)(frameBufferStart + write_pointer));
        write_pointer += 2;
    }
}
// extern "C" __irq void LCD_EXTI_IRQHandler(void)
// {
//     /* Make sure that interrupt flag is set */
//     if (EXTI_GetITStatus(LCD_TE_EXTI_Line) != RESET)
//     {
//         OSWrappers::signalVSync();
//         displaySetArea(0, 0, DISP_HOR_RESOLUTION, DISP_VER_RESOLUTION); //force update the whole screen here by blunt force
//         displayXferFB(0, 0, DISP_HOR_RESOLUTION, DISP_VER_RESOLUTION, Bank1_ili9327_D);
//         //touchgfx::GPIO::toggle(touchgfx::GPIO::VSYNC_FREQ); //debug
//         /* Clear interrupt flag */
//         EXTI_ClearITPendingBit(LCD_TE_EXTI_Line);
//     }
// }